//#pragma once

#ifndef __BAYESIANFILTER_INCLUDED
#define __BAYESIANFILTER_INCLUDED

#include <string>
#include <map>
#include <set>

#include "Lock.h"

using namespace std;

class Test_BayesianFilter;
class BayesianFilterSerializer;

	class EmptyTagSet { };
	class TagAlreadyExistsException { };
	class TagNotExistsException { };

	struct __BayesianTag
	{
		unsigned long pos;	
		unsigned long wordCount;
		unsigned long trueCount;
		unsigned long falseCount;
	};

	struct __BayesianProbability
	{
		__BayesianProbability ();

		unsigned long trueCount;
		unsigned long falseCount;

		__BayesianProbability operator= (const __BayesianProbability& rval);
	};

	struct BayesianFilterResult
	{
		string Tag;
		double Witness;
		double HitRatio;
	};

	class BayesianFilter
	{
	friend class BayesianFilterSerializer;
	friend class Test_BayesianFilter;

	public:
		BayesianFilter(void);
		~BayesianFilter(void);

		void Train	 ( set<string>& words , set<string>& tags );
		void Retrain ( set<string>& words , set<string>& removeTags , set<string>& addTags );

		void AddTag		( string tagName );
		void RemoveTag	( string tagName );

		set<BayesianFilterResult*> Classify	( set<string>& words );

		double		ProbabilityThreshold;

	protected:
		Lock lock;

		map<string,__BayesianTag*>			tags;
		map<string,__BayesianProbability*>	words;

		unsigned long* FindTagPos ( set<string>& trainTags );
		__BayesianProbability* ProbabilityRow ( string word );

		enum UpdateModes
		{
			TrainMode,
			RemoveMode,
			AddMode
		};

		void UpdateRow ( __BayesianProbability* p , unsigned long* tagPos , int size , UpdateModes updateMode );
		void Train	 ( set<string>& words , set<string>& tags , UpdateModes updateMode );
	};
	
#endif
